package cn.itcast.nems.studentrecord.service.impl;

import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.ic.common.exception.v2.bean.BizStatusEnum;
import cn.itcast.nems.discount.api.DiscountApi;
import cn.itcast.nems.discount.dto.DiscountSummaryDTO;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecord;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecordDiscount;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecordOrderRelationship;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecordStudentRelationship;
import cn.itcast.nems.studentrecord.dao.mapper.StudentRecordOrderRelationshipMapper;
import cn.itcast.nems.studentrecord.dao.mapper.StudentRecordStudentRelationshipMapper;
import cn.itcast.nems.studentrecord.dto.change.StudentRecordChangeDiscountDTO;
import cn.itcast.nems.studentrecord.dto.change.StudentRecordCreateDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordCreateMessageDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordValidMessageDTO;
import cn.itcast.nems.studentrecord.enumeration.StudentRecordStateEnum;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordCreateService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordDiscountService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordMessageService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author liyong
 * create: 2023-11-15 11:16:33
 **/
@Service
@Slf4j
@AllArgsConstructor
public class StudentRecordCreateServiceImpl implements StudentRecordCreateService {
    private final StudentRecordService studentRecordService;
    private final StudentRecordOrderRelationshipMapper studentRecordOrderRelationshipMapper;
    private final StudentRecordStudentRelationshipMapper studentRecordStudentRelationshipMapper;
    private final StudentRecordDiscountService studentRecordDiscountService;
    private final StudentRecordMessageService studentRecordMessageService;
    private final DiscountApi discountApi;

    @Override
    @Transactional
    public StudentRecord createStudentRecord(StudentRecordCreateDTO dto) {
        final StudentRecord oldStudentRecord = this.studentRecordService.findInClazzStudentRecord(dto.getStudentId(), dto.getClazzId());
        if (oldStudentRecord != null) {
            if (dto.isRequiredNew()) {
                BizExceptionProducer.throwServerError(BizStatusEnum.INTERNAL_SERVER_ERROR.toString(),
                        "要进入班的学籍已经存在(学员ID: %d 班级ID: %d)",
                        dto.getStudentId(),
                        dto.getClazzId());
            }
            return this.update(oldStudentRecord, dto);
        } else {
            return this.create(dto);
        }
    }

    private StudentRecord update(StudentRecord oldStudentRecord, StudentRecordCreateDTO dto) {
        final Map<Integer, DiscountSummaryDTO> discounts = this.findDiscounts(dto.getDiscounts());
        StudentRecordCreator creator = new StudentRecordCreator(dto, discounts);
        final List<StudentRecordDiscount> studentRecordDiscounts = creator.createStudentRecordDiscounts(oldStudentRecord);
        this.studentRecordDiscountService.updateDiscounts(oldStudentRecord.getId(), studentRecordDiscounts);
        final StudentRecord update = creator.updateStudentRecord(oldStudentRecord);
        this.studentRecordService.updateStudentRecordById(update);
        final String orderId = dto.getOrderId();
        if (StringUtils.hasText(orderId)) {
            final Set<String> orderIds = this.studentRecordOrderRelationshipMapper.selectOrderIds(oldStudentRecord.getId());
            if (!orderIds.contains(orderId)) {
                this.addStudentRecordOrderRelationship(oldStudentRecord.getId(), orderId);
            }
        }
        return oldStudentRecord;
    }

    private StudentRecord create(StudentRecordCreateDTO dto) {
        final Map<Integer, DiscountSummaryDTO> discounts = this.findDiscounts(dto.getDiscounts());
        StudentRecordCreator creator = new StudentRecordCreator(dto, discounts);
        final StudentRecord studentRecord = creator.createStudentRecord();
        studentRecordService.addStudentRecord(studentRecord);
        String id = studentRecord.getId();
        final List<StudentRecordDiscount> studentRecordDiscounts = creator.createStudentRecordDiscounts(studentRecord);
        this.studentRecordDiscountService.saveBatch(studentRecordDiscounts);
        this.addStudentRecordStudentRelationship(id, dto.getStudentId());
        final String orderId = dto.getOrderId();
        if (StringUtils.hasText(orderId)) {
            this.addStudentRecordOrderRelationship(id, orderId);
        }
        sendCreateStudentRecordMessage(dto, id, studentRecord);
        if (StudentRecordStateEnum.VALID == dto.getState()) {
            this.sendValidStudentRecordMessage(studentRecord);
        }
        return studentRecord;
    }

    private void sendCreateStudentRecordMessage(StudentRecordCreateDTO dto, String id, StudentRecord studentRecord) {
        StudentRecordCreateMessageDTO messageDTO = new StudentRecordCreateMessageDTO();
        BeanUtils.copyProperties(dto, messageDTO);
        messageDTO.setStudentRecordId(id);
        messageDTO.setBizDateTime(studentRecord.getCreatedDatetime());
        messageDTO.setTenantId(studentRecord.getTenantId());
        messageDTO.setSubtenantId(studentRecord.getSubtenantId());
        this.studentRecordMessageService.studentRecordCreated(messageDTO);
    }

    private void sendValidStudentRecordMessage(StudentRecord studentRecord) {
        StudentRecordValidMessageDTO message = new StudentRecordValidMessageDTO();
        message.setStudentRecordId(studentRecord.getId());
        message.setBizDateTime(LocalDateTime.now());
        message.setTenantId(studentRecord.getTenantId());
        message.setSubtenantId(studentRecord.getSubtenantId());
        message.setClazzId(studentRecord.getClazzId());
        this.studentRecordMessageService.studentRecordValid(message);
    }

    private void addStudentRecordOrderRelationship(String studentRecordId, String orderId) {
        StudentRecordOrderRelationship relationship = new StudentRecordOrderRelationship();
        relationship.setStudentRecordId(studentRecordId);
        relationship.setOrderId(orderId);
        this.studentRecordOrderRelationshipMapper.insert(relationship);
    }

    private void addStudentRecordStudentRelationship(String studentRecordId, int studentId) {
        StudentRecordStudentRelationship studentRelationship = new StudentRecordStudentRelationship();
        studentRelationship.setStudentRecordId(studentRecordId);
        studentRelationship.setStudentId(studentId);
        studentRelationship.setState(Byte.valueOf("1"));
        this.studentRecordStudentRelationshipMapper.insert(studentRelationship);
    }

    private Map<Integer, DiscountSummaryDTO> findDiscounts(List<StudentRecordChangeDiscountDTO> discounts) {
        Map<Integer, DiscountSummaryDTO> result = new LinkedHashMap<>();
        if (discounts != null && !discounts.isEmpty()) {
            discounts.forEach(d -> {
                final DiscountSummaryDTO summary = this.discountApi.getSummaryById(d.getDiscountId());
                result.put(summary.getId(), summary);
            });
        }
        return result;
    }
}
